/*
 * Licensed to the 南京汇海交通科技有限公司
 *
 * Copyright (c) 2025.
 * All rights reserved.
 *
 * 本软件属南京汇海交通科技有限公司所有，在未获得南京汇海交通科技有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.chframework.common.extend;

import com.chframework.common.exception.UtilityException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Base64;

/**
 * 网络报文安全传输时，对称加密
 */
public class HttpsHelper {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 解密
     *
     * @param base64     经过base64编码密文
     * @param encryptKey 秘钥
     */
    public static String decrypt(String base64, String encryptKey) throws UtilityException {
//CHECKSTYLE:OFF
        try {
            // 1 对密文进行base64位解码
            byte[] result = Base64.getDecoder().decode(base64);
            // 2 在密文的字节数组中，从索引0的位置开始复制16个字节；在初始向量iv的字节数组中，从索引0的位置开始填充被复制的16个字节。
            byte[] iv = new byte[16];
            System.arraycopy(result, 0, iv, 0, iv.length);
            // 3 在密文的字节数组中，从索引16的位置开始复制剩余的全部字节；在数据报文的字节数组中，从索引0的位置开始填充被复制的剩余全部字节。
            byte[] data = new byte[result.length - iv.length];
            System.arraycopy(result, iv.length, data, 0, data.length);
            // 4 使用SHA256对秘钥进行哈希得到密钥key
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] key = digest.digest(encryptKey.getBytes(StandardCharsets.UTF_8));
            // 5 使用AES算法对数据报文进行解密
            Cipher cipher = Cipher.getInstance("AES/CBC/NOPADDING");
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
            byte[] sourceBuffer = cipher.doFinal(data);
            // 6 从解密后的字节数组中获取数据报文的字节数组
            if (sourceBuffer.length > 0) {
                // 6.1 定义字节数组的截取位置
                int position = sourceBuffer.length - 1;
                // 6.2 获取字节数组的截取位置
                while (position >= 0 && sourceBuffer[position] <= iv.length) {
                    position--;
                }
                // 6.3 通过截取获得数据报文的字节数组
                if (position != sourceBuffer.length - 1) {
                    byte[] tmpBuffer = new byte[position + 1];
                    System.arraycopy(sourceBuffer, 0, tmpBuffer, 0, position + 1);
                    sourceBuffer = tmpBuffer;
                }
            }

            return new String(sourceBuffer, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
//CHECKSTYLE:ON
    }

    /**
     * 加密
     *
     * @param source     数据报文
     * @param encryptKey 秘钥
     */
    public static String encrypt(String source, String encryptKey) throws UtilityException {
//CHECKSTYLE:OFF
        try {
            // 1 使用SHA256对EncryptKey进行哈希得到密钥key；
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] key = digest.digest(encryptKey.getBytes(StandardCharsets.UTF_8));
            // 2 生成16个字节的随机数作为初始向量iv；
            byte[] iv = SecureRandom.getInstanceStrong().generateSeed(16);
            // 3 使用PKCS7Padding方式将事件内容进行填充；
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
            // 4 使用iv和key对数据报文加密；
            byte[] data = cipher.doFinal(source.getBytes(StandardCharsets.UTF_8));
            // 5 应用收到的密文encrypt为base64(iv+数据报文)
            byte[] result = new byte[iv.length + data.length];
            System.arraycopy(iv, 0, result, 0, iv.length);
            System.arraycopy(data, 0, result, iv.length, data.length);

            return Base64.getEncoder().encodeToString(result);
        } catch (Exception e) {
            throw new UtilityException(e);
        }
//CHECKSTYLE:ON
    }

}
